/*
 * Copyright (C) 2012 JiangHongTiao
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package sk.lieskove.jianghongtiao.paris.core.classify;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.apache.log4j.Logger;
import sk.lieskove.jianghongtiao.common.utils.PropertiesUtils;
import sk.lieskove.jianghongtiao.commonpersist.Persist;
import sk.lieskove.jianghongtiao.paris.core.classify.enums.SupportedClassifiers;
import sk.lieskove.jianghongtiao.paris.core.persistence.TestSet;
import sk.lieskove.jianghongtiao.paris.core.persistence.TrainSet;
import sk.lieskove.jianghongtiao.websearch.document.preprocessing.SupportedLanguages;
import sk.lieskove.jianghongtiao.websearch.enums.DocumentType;
import sk.lieskove.jianghongtiao.websearch.persistence.ClassificationStorage;
import weka.classifiers.Evaluation;

/**
 * 
 * @author xjuraj e-mail: jjurco.sk_gmail.com
 */
public class BatchClassification implements Serializable {

    private transient static Logger log = Logger.getLogger(BatchClassification.class);
    private transient PropertiesUtils pu = new PropertiesUtils(BatchClassification.class);

    private static class Warehouse {

        private TestSet testSet;
        private TrainSet trainSet;
        private ThreadArffMaker testArffMaker;
        private ThreadArffMaker trainArffMaker;

        public ThreadArffMaker getTestArffMaker() {
            return testArffMaker;
        }

        public void setTestArffMaker(ThreadArffMaker testArffMaker) {
            this.testArffMaker = testArffMaker;
        }

        public ThreadArffMaker getTrainArffMaker() {
            return trainArffMaker;
        }

        public void setTrainArffMaker(ThreadArffMaker trainArffMaker) {
            this.trainArffMaker = trainArffMaker;
        }

        public TestSet getTestSet() {
            return testSet;
        }

        public void setTestSet(TestSet testSet) {
            this.testSet = testSet;
        }

        public TrainSet getTrainSet() {
            return trainSet;
        }

        public void setTrainSet(TrainSet trainSet) {
            this.trainSet = trainSet;
        }
    }

    public static void batchClassify(BatchClassificationProperties bcp) {
        batchClassify(bcp.getClassifiers(), bcp.getLoops(), bcp.getLanguages(),
                bcp.getWordsToKeep(), bcp.getJoinDocTypesString(), bcp.getBaseline(),
                bcp.getDocumentTypes(), bcp.getClassificationGroup());
    }

    public static void batchClassify(List<String> classifiers, int loops,
            List<String> languages, int wordsToKeep, String joinDocTypesString,
            Double baseline, DocumentType[] documentTypes, String classifierGroup) {
//        final DocumentType[] documentTypes = new DocumentType[]{DocumentType.INFORMATICS, DocumentType.MANAGER, DocumentType.INFO_MANAGER};
//        final Double baseline = new Double(60);
//        final SupportedLanguages language = SupportedLanguages.Czech;
//        final String joinDocTypesString = null;
//        int wordsToKeep = 500;
//        List<Classifier> classifiers = null;
//        int loops = 50;
//        List<String> languages = new ArrayList<String>(1);
//        languages.add(language.name());
        SupportedLanguages language = SupportedLanguages.valueOf(languages.get(0));
        Timestamp compTime = new Timestamp((new Date()).getTime());

        List<Warehouse> warehouse = new ArrayList<Warehouse>();
        for (int i = 0; i < loops; i++) {
            Warehouse w = new Warehouse();

            LearnSetCreator learnSet = new LearnSetCreator();
            Map<String, List<ClassificationStorage>> trainSet =
                    learnSet.createLearnSet(baseline, documentTypes, language, joinDocTypesString);
            Map<String, List<ClassificationStorage>> testSet =
                    learnSet.createLearnSet(baseline, documentTypes, language, joinDocTypesString);

            ThreadArffMaker trainArff = new ThreadArffMaker(trainSet,
                    "Arff train set create", languages, wordsToKeep);
            ThreadArffMaker testArff = new ThreadArffMaker(testSet,
                    "Arff test set create", languages, wordsToKeep);
            trainArff.start();
            testArff.start();
            
            w.setTestSet(learnSet.createTestSet(testSet, language));
            w.setTrainSet(learnSet.createTrainSet(trainSet, language));
            w.setTestArffMaker(testArff);
            w.setTrainArffMaker(trainArff);
            
            warehouse.add(w);
        }
        for (Warehouse w : warehouse) {
            try {
                w.getTestArffMaker().join();
                w.getTrainArffMaker().join();
            } catch (InterruptedException ex) {
                log.error("interrupted exception", ex);
            }
        }

        Persist p = Persist.getSingleton();
        for (Warehouse w : warehouse) {
            List<ThreadClassifier> tcs = new ArrayList<ThreadClassifier>();
            //************classification*******************
            for (String classifier : classifiers) {
                try {
                    ThreadClassifier tc = new ThreadClassifier(
                            SupportedClassifiers.byName(classifier),
                            w.getTrainArffMaker().getInstances(),
                            w.getTestArffMaker().getInstances(),
                            new Evaluation(w.getTestArffMaker().getInstances()),
                            w.getTestSet().copy(), 
                            w.getTrainSet().copy(),
                            classifier + " classifier", 
                            classifierGroup, 
                            compTime);
                    tc.start();
                    tc.join();
                    tcs.add(tc);
                } catch (Exception ex) {
                    log.error("Exception thrown: ", ex);
                }
            }
            for (ThreadClassifier threadClassifier : tcs) {
                try {
                    System.out.println("Actually waiting for: "+threadClassifier.getName());
                    threadClassifier.join();
                } catch (InterruptedException ex) {
                    log.error("Interrupted exception", ex);
                }
                p.persist(threadClassifier.getClassifierStatistics());
            }
        }

    }
}
